﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Persistencia.Repositorios;
using Entidades;
using Common;

namespace Controladores
{
    public class GuionControlador
    {
        readonly GuionRepositorio _guionRepositorio = new GuionRepositorio();

        #region Guion

        /// <summary>
        /// Devuelve un Guion según su Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Guion ObtenerGuion(int id)
        {
            return _guionRepositorio.ObtenerGuion(id);
        }

        /// <summary>
        /// Devuelve todos los Guiones, según un filtro y paginación
        /// </summary>
        /// <param name="paginacion"></param>
        /// <param name="filtro"></param>
        /// <returns></returns>
        public List<Guion> ObtenerGuiones(Data.Pagination paginacion, string filtro)
        {
            List<Guion> guiones = new List<Guion>();
            try
            {
                guiones = _guionRepositorio.ObtenerGuiones(paginacion, filtro);
            }
            catch (Exception)
            {
                throw;
            }
            return guiones;
        }

        /// <summary>
        /// Devuelve los Guiones asociados a un Actor
        /// </summary>
        /// <param name="idActor"></param>
        /// <param name="paginacion"></param>
        /// <param name="filtro"></param>
        /// <returns></returns>
        public List<GuionItem> ObtenerGuionesDelActor(int idActor, Data.Pagination paginacion, string filtro)
        {
            List<GuionItem> guiones = new List<GuionItem>();
            try
            {
                guiones = _guionRepositorio.ObtenerGuionesDelActor(idActor, paginacion, filtro);
            }
            catch (Exception)
            {
                throw;
            }
            return guiones;
        }

        /// <summary>
        /// Devuelva una lista de Guiones que están Pendientes de Pago
        /// [Opcional] Id Tipo de Usuario
        /// [Opcional] Id Categoría de Usuario
        /// [Opcional] Id Usuario
        /// [Opcional] Id Tipo Usuario a ignorar
        /// </summary>
        /// <param name="idProyecto"></param>
        /// <param name="idTipoUsuario"></param>
        /// <param name="idCategoriaUsuario"></param>
        /// <param name="idUsuario"></param>
        /// <param name="idTipoUsuarioIgnorado"></param>
        /// <returns></returns>
        public IList<Guion> ObtenerGuionesPendientesDePago(int idProyecto, int? idTipoUsuario, int? idCategoriaUsuario = null, int? idUsuario = null, int? idTipoUsuarioIgnorado = null)
        {
            return _guionRepositorio.ObtenerGuionesPendientesDePago(idProyecto, idTipoUsuario, idCategoriaUsuario, idUsuario, idTipoUsuarioIgnorado);
        }

        ///// <summary>
        ///// Obtiene los Guiones en los que participó un Usuario, como Adaptador/Director/Mezclador/Traductor/Actor
        ///// </summary>
        ///// <param name="idUsuario"></param>
        ///// <returns></returns>
        //public IList<Guion> ObtenerGuiones(int? idUsuario = null)
        //{
        //    return _guionRepositorio.ObtenerGuiones(idUsuario);
        //}

        /// <summary>
        /// Obtiene los Guiones (activos? de un Proyecto?) en los que participó un Usuario, como Adaptador/Director/Mezclador/Traductor/Actor/UsuarioCreador
        /// </summary>
        /// <param name="idUsuario"></param>
        /// <param name="idProyecto"></param>
        /// <param name="activos"></param>
        /// <returns></returns>
        public IList<Guion> ObtenerGuiones(int? idUsuario = null, int? idProyecto = null, bool activos = true)
        {
            try
            {
                var parametros = new Common.Data.ParameterList();
                    parametros.AddParameter("activo", activos);
                    parametros.AddParameter("id_usuario", idUsuario);
                    parametros.AddParameter("id_proyecto", idProyecto);
                return new RepositorioBase<Guion>.StoredProcedure().GetList(WellKnownKeys.StoredProcedures.Guiones_By_User_GET, parametros.List);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Devuelve el total de Guiones, según un filtro
        /// </summary>
        /// <param name="filtro"></param>
        /// <returns></returns>
        public int ObtenerTotalGuiones(string filtro)
        {
            try
            {
                return _guionRepositorio.ObtenerTotalGuiones(filtro);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Guarda un Guión
        /// <param name="guion"></param>
        /// </summary>
        /// <returns></returns>
        public bool GuardarGuion(Guion guion)
        {
            return _guionRepositorio.GuardarGuion(guion);
        }

        /// <summary>
        /// Agregar Transiciones de Estado a un Guión.
        /// NOTA: Si faltan Transiciones con menor N° de Orden, las agrega previamente al Estado actual
        /// </summary>
        /// <param name="guion"></param>
        /// <param name="idEstadoNuevo"></param>
        /// <param name="fecha"></param>
        /// <param name="usuario"></param>
        /// <param name="eliminarTransicionesExistente"></param>
        public static void AgregarTransicionDeEstado(Guion guion, int idEstadoNuevo, DateTime fecha, int idUsuario, bool eliminarTransicionesExistente = false)
        {
            var controladorGuionEstado = new ControladorBase<GuionEstado>();

            if (guion.TransicionDeEstados == null)
                guion.TransicionDeEstados = new List<GuionEstadoTransicion>();

            if (eliminarTransicionesExistente)
                guion.TransicionDeEstados.Clear();

            var ultimoEstado = guion.TransicionDeEstados.Any() ? guion.TransicionDeEstados.Last().EstadoNuevo : null;    

            var estadoNuevo = controladorGuionEstado.ObtenerEntidad(idEstadoNuevo);

            var usuario = new ControladorBase<Usuario>().ObtenerEntidad(idUsuario);

            var estadosGuion = controladorGuionEstado.ObtenerEntidades().OrderBy(x => x.Orden).ToList();
            foreach (var estadoAInsertar in estadosGuion)
            {
                if (estadoAInsertar.Orden > estadoNuevo.Orden)
                    break;

                var existeEstado = guion.TransicionDeEstados.Any(x => x.EstadoNuevo.Id == estadoAInsertar.Id);
                var noEsElUltimoEstado = ultimoEstado == null || ultimoEstado.Id != estadoAInsertar.Id;
                var esElEstadoDeseado = estadoNuevo.Id == estadoAInsertar.Id;
                if ( (!existeEstado) || (existeEstado && noEsElUltimoEstado && esElEstadoDeseado) )
                {
                    var transicionEstado = new GuionEstadoTransicion
                    {
                        EstadoAnterior = ultimoEstado,
                        EstadoNuevo = estadoAInsertar,
                        Fecha = fecha,
                        Usuario = usuario,
                        Guion = guion
                    };
                    guion.TransicionDeEstados.Add(transicionEstado);
                    ultimoEstado = estadoAInsertar;
                }
            }
        }

        /// <summary>
        /// Agrega una Transición de Autorización
        /// </summary>
        /// <param name="guion"></param>
        /// <param name="idAutorizacion"></param>
        /// <param name="fecha"></param>
        /// <param name="idUsuario"></param>
        /// <param name="eliminarExistentes"></param>
        public static void AgregarTransicionDeAutorizacion(Guion guion, int idAutorizacion, DateTime fecha, int idUsuario, bool eliminarExistentes = false)
        {
            var autorizacion = new ControladorBase<GuionAutorizacion>().ObtenerEntidad(idAutorizacion);

            if (guion.TransicionDeAutorizaciones == null)
                guion.TransicionDeAutorizaciones = new List<GuionAutorizacionTransicion>();

            if (eliminarExistentes)
                guion.TransicionDeAutorizaciones.Clear();

            var usuario = new ControladorBase<Usuario>().ObtenerEntidad(idUsuario);

            var transicionAutorizacion = new GuionAutorizacionTransicion
            {
                Guion = guion,
                Autorizacion = autorizacion,
                FechaInicio = fecha,
                UsuarioInicio = usuario
            };

            guion.TransicionDeAutorizaciones.Add(transicionAutorizacion);            
        }

        /// <summary>
        /// Actualiza una Transición de Autorización
        /// </summary>
        /// <param name="guion"></param>
        /// <param name="idTransicionAutorizacion"></param>
        /// <param name="aprobada"></param>
        /// <param name="comentarios"></param>
        /// <param name="fechaFin"></param>
        /// <param name="usuarioFin"></param>
        public static void ActualizarTransicionDeAutorizacion(Guion guion, int idTransicionAutorizacion, bool aprobada, string comentarios, DateTime fechaFin, Usuario usuarioFin, Usuario usuarioNotificado = null)
        {
            var transicionAutorizacion = guion.TransicionDeAutorizaciones.FirstOrDefault(x => x.Id == idTransicionAutorizacion);
            if (transicionAutorizacion != null)
            {
                transicionAutorizacion.Aprobada = aprobada;
                transicionAutorizacion.Comentarios = comentarios;
                transicionAutorizacion.FechaFin = fechaFin;
                transicionAutorizacion.UsuarioFin = usuarioFin;
                transicionAutorizacion.UsuarioNotificado = usuarioNotificado;
            }
        }

        #endregion

        #region Guion Item

        /// <summary>
        /// Devuelve un GuionItem según su Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public GuionItem ObtenerGuionItem(int id)
        {
            return _guionRepositorio.ObtenerGuionItem(id);
        }


        /// <summary>
        /// Guarda el Ítem de un Guión
        /// </summary>
        /// <returns></returns>
        public bool GuardarItem(GuionItem item)
        {
            return _guionRepositorio.GuardarItem(item);
        }

        /// <summary>
        /// Elimina el Ítem de un Guión
        /// </summary>
        /// <returns></returns>
        public bool EliminarItem(GuionItem item)
        {
            return _guionRepositorio.EliminarItem(item);
        }

        #endregion

        #region Guion Estado

        /// <summary>
        /// Devuelve un GuionEstado según su Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public GuionEstado ObtenerGuionEstado(int id)
        {
            return _guionRepositorio.ObtenerGuionEstado(id);
        }

        /// <summary>
        /// Devuelve todos los GuionEstado
        /// </summary>
        /// <returns></returns>
        public List<GuionEstado> ObtenerEstadosGuion()
        {
            List<GuionEstado> estados = new List<GuionEstado>();
            try
            {
                estados = _guionRepositorio.ObtenerEstadosGuion();
            }
            catch (Exception)
            {
                throw;
            }
            return estados;
        }

        #endregion

        #region Costo

        /// <summary>
        /// Devuelve el Costo de un Guion
        /// </summary>
        /// <param name="idGuion"></param>
        /// <returns></returns>
        public GuionCosto ObtenerCostoGuion(int idGuion)
        {
            return _guionRepositorio.ObtenerGuionCosto(idGuion);
        }

        /// <summary>
        /// Guarda un GuionCosto
        /// </summary>
        /// <param name="guionCosto"></param>
        /// <returns></returns>
        public bool GuardarGuionCosto(GuionCosto guionCosto)
        {
            return _guionRepositorio.GuardarGuionCosto(guionCosto);
        }

        /// <summary>
        /// Copia los datos del Costo Maestro a un (nuevo) CostoGuion
        /// </summary>
        /// <param name="costoMaestro"></param>
        /// <returns></returns>
        public GuionCosto CopiarCostoMaestro(Costo costo)
        {
            var guionCosto = new GuionCosto();
            if (costo != null)
            {
                //guionCosto.Id = 
                //guionCosto.Guion = 
                guionCosto.Adaptacion       = costo.Adaptacion;
                guionCosto.Cancion          = costo.Cancion;
                guionCosto.Coro             = costo.Coro;
                guionCosto.Direccion        = costo.Direccion;
                guionCosto.LoopMinimo       = costo.LoopMinimo;
                guionCosto.Loops            = costo.Loops;
                guionCosto.Mezcla           = costo.Mezcla;
                guionCosto.Palabras         = costo.Palabras;
                guionCosto.Traduccion       = costo.Traduccion;
                guionCosto.Temporizacion    = costo.Temporizacion;
            }
            return guionCosto;
        }

        #endregion

        #region Tipo Cancion

        /// <summary>
        /// Devuelve un TipoCancion según su Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public TipoCancion ObtenerTipoCancion(int id)
        {
            return _guionRepositorio.ObtenerTipoCancion(id);
        }

        /// <summary>
        /// Deuelve todos los TipoCancion
        /// </summary>
        /// <returns></returns>
        public List<TipoCancion> ObtenerTiposCancion()
        {
            var tipos = new List<TipoCancion>();
            try
            {
                tipos = _guionRepositorio.ObtenerTiposCancion();
            }
            catch (Exception)
            {
                throw;
            }
            return tipos;
        }

        #endregion
    }
}
